package com.imddy.gkrpc.server;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import org.apache.commons.io.IOUtils;

import com.imddy.gkrpc.Request;
import com.imddy.gkrpc.Response;
import com.imddy.gkrpc.codec.Decoder;
import com.imddy.gkrpc.codec.Encoder;
import com.imddy.gkrpc.common.utils.ReflectionUtils;
import com.imddy.gkrpc.transport.RequestHandler;
import com.imddy.gkrpc.transport.TransportServer;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class RpcServer {

	private RpcServerConfig config;
	private TransportServer transportServer;
	private Encoder encoder;
	private Decoder decoder;
	private ServiceManager serviceManager;
	private ServiceInvoker serviceInvoker;
	
	public RpcServer() {
	}
	
	public RpcServer(RpcServerConfig config) {
		this.config = config;
		// net
		this.transportServer = ReflectionUtils.newInstance(config.getTransportServerClass());
		// codec
		this.encoder = ReflectionUtils.newInstance(config.getEncoderClass());
		this.decoder = ReflectionUtils.newInstance(config.getDecoderClass());
		// service
		this.serviceManager = new ServiceManager();
		this.serviceInvoker = new ServiceInvoker();
	}
	
	private RequestHandler requestHandler = new RequestHandler() {
		
		@Override
		public void onHandler(InputStream recive, OutputStream toResp) {
			// TODO Auto-generated method stub
			Response response = new Response();
			
			try {
				byte[] inBytes = IOUtils.readFully(recive, recive.available());
				Request request = decoder.decoder(inBytes, Request.class);
				log.info("get request: {}", request);
				
				ServiceInstance sis = serviceManager.lookup(request);
				Object ret = serviceInvoker.invoke(sis, request);
				
				response.setData(ret);
				
			} catch (IOException e) {
				// TODO Auto-generated catch block
				log.warn(e.getMessage());
				response.setCode(1);
				response.setMessage("RpcServer got error: "
						+ e.getClass().getName()
						+ " : " + e.getMessage());
				e.printStackTrace();
			} finally {
				try {
					byte[] outBytes = encoder.encoder(response);
					toResp.write(outBytes);
					log.info("response client");
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
					log.warn(e.getMessage(), e);
				}
			}
			
		}
	};
	
	public <T> void registe(Class<T> interfaceClass, T bean) {
		serviceManager.registe(interfaceClass, bean);
	}
	
	public void start() {
		this.transportServer.init(config.getPort(), requestHandler);
		this.transportServer.start();
	}
	
	public void stop() {
		this.transportServer.stop();
	}
	
	
	
	
}
